package com.example.bicycle.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.bicycle.domain.dto.UserLocationDto;
import com.example.bicycle.domain.entity.Battery;
import com.example.bicycle.domain.entity.ElectricBike;
import com.example.bicycle.domain.entity.RideRecord;
import com.example.bicycle.domain.mqtt.PublishSettingMessageVo;
import com.example.bicycle.domain.vo.BikeLocationVo;
import com.example.bicycle.domain.vo.PageVo;
import com.example.bicycle.mapper.ElectricBikeMapper;
import com.example.bicycle.service.BatteryService;
import com.example.bicycle.service.ElectricBikeService;
import com.example.bicycle.service.RideRecordService;
import com.example.bicycle.utils.DistanceUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.example.bicycle.domain.enums.AppHttpCodeEnum.*;

/**
 * (ElectricBike)表服务实现类
 *
 * @author makejava
 * @since 2023-08-02 21:29:25
 */
@Service("electricBikeService")
public class ElectricBikeServiceImpl extends ServiceImpl<ElectricBikeMapper, ElectricBike> implements ElectricBikeService {
    private final BatteryService batteryService;
    private final RideRecordService rideRecordService;


    @Autowired
    public ElectricBikeServiceImpl(BatteryService batteryService, RideRecordService rideRecordService) {
        this.batteryService = batteryService;
        this.rideRecordService = rideRecordService;
    }

    /**
     * 列表用户位置
     *
     * @param userLocationDto 用户位置dto
     * @return {@link List}<{@link ElectricBike}>
     */
    private List<BikeLocationVo> listByUserLocation(UserLocationDto userLocationDto) {
        List<ElectricBike> list = list();
        List<BikeLocationVo> bikeLocationVos = new ArrayList<>();
        for (ElectricBike electricBike : list) {
            bikeLocationVos.add(new BikeLocationVo(electricBike));
        }
        Float lon2 = userLocationDto.getLongitude();
        Float lat2 = userLocationDto.getLatitude();
        for (BikeLocationVo bikeLocationVo : bikeLocationVos) {
            bikeLocationVo.setDistance(DistanceUtils.getDistance(bikeLocationVo.getBike().getLongitude(),bikeLocationVo.getBike().getLatitude(),lon2,lat2));
            // 放入电池信息
            Battery byId = batteryService.getById(bikeLocationVo.getBike().getBatteryId());
            byId.calculateVdElectricity();
            bikeLocationVo.setBattery(byId);
        }
        // 使用距离比较器对列表进行排序
        bikeLocationVos.sort(Comparator.comparingDouble(BikeLocationVo::getDistance));
        return bikeLocationVos;
    }
    /**
     * 检索所有车辆列表根据用户位置
     *
     * @param pageSize        页面大小
     * @param pageNum         页面num
     * @param userLocationDto 用户位置dto
     * @return {@link PageVo}
     */
    @Override
    public PageVo listByUserLocation(int pageNum, int pageSize, UserLocationDto userLocationDto) {
        List<BikeLocationVo> electricBikes = listByUserLocation(userLocationDto);
        return getPage(pageNum, pageSize, electricBikes);
    }

    /**
     * 可用自行车由用户位置
     *
     * @param pageSize        页面大小
     * @param pageNum         页面num
     * @param userLocationDto 用户位置dto
     * @return {@link PageVo}
     */
    @Override
    public PageVo availableBikeByUserLocation(int pageNum, int pageSize, UserLocationDto userLocationDto) {
        List<BikeLocationVo> electricBikes = listByUserLocation(userLocationDto);
        /* 没有处于被使用状态且电池电量大于10% */
        electricBikes.removeIf(bike -> bike.getBike().getIsUsing() != 0);
        electricBikes.removeIf(bike -> bike.getBattery().getVoltage_d() < 0.1);
        return getPage(pageNum,pageSize,electricBikes);
    }

    @Override
    public boolean rent(int bikeId, UserLocationDto userLocationDto) {
        try{
            /* 第一步先打开bike的开关并设置使用状态，改变数据库并发送MQTT服务器
            * 注意先判断以免出现恶意租借情况:
            * 1. 后端租已经租出去的车(包括当前这个人租的车）
            * 2. 一人租多辆车（行程未结束）
            * 3. id是否跟登录本人一致
            * */
            ElectricBike electricBike = getById(bikeId);
            if(electricBike.getIsUsing()==BIKE_STATUS_ON.getCode()){
                return false;
            }
            RideRecord latestRideRecord = rideRecordService.getLatestRecordByUserId(userLocationDto.getUserId());
            /* 根据最新的数据去判断是否租多辆车：1.没有租车记录 2.有租车记录但没结束时间 */
            if(latestRideRecord!=null&&latestRideRecord.getEndTime()==null&&latestRideRecord.getBikeId()!=bikeId){
                return false;
            }
            if(userLocationDto.getUserId()==StpUtil.getLoginIdByToken(StpUtil.getTokenValue())){
                return false;
            }

            electricBike.setSwitchState(BIKE_SWITCH_ON.getCode());//1为开 0为关
            electricBike.setIsUsing(BIKE_STATUS_ON.getCode());
            /* 存入表中，注意要最后存，不然没有修改设备就存了不合理 */
            updateById(electricBike);
            /* 第二部是存入RideRecord表中 */
            RideRecord rideRecord = new RideRecord();
            rideRecord.setBikeId(bikeId);
            rideRecord.setUserId(userLocationDto.getUserId());
            rideRecord.setStartTime(new Date(System.currentTimeMillis()));
            rideRecord.setStartLongitude(electricBike.getLongitude());
            rideRecord.setStartLatitude(electricBike.getLatitude());
            rideRecordService.save(rideRecord);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public boolean lock(int bikeId, UserLocationDto userLocationDto) {
        /* 锁车先判断是否是他租赁的，是则关闭bike开关 */
        try{
            RideRecord rideRecord = rideRecordService.getLatestRecordByBikeId(bikeId);
            ElectricBike electricBike = getById(bikeId);
            if(rideRecord.getUserId() == userLocationDto.getUserId()&&electricBike.getIsUsing()==1){
                electricBike.setSwitchState(BIKE_SWITCH_OFF.getCode());

                updateById(electricBike);
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public boolean unlock(int bikeId, UserLocationDto userLocationDto) {
        /* 锁车先判断是否是他租赁的，是则关闭bike开关 */
        try{
            RideRecord rideRecord = rideRecordService.getLatestRecordByBikeId(bikeId);
            ElectricBike electricBike = getById(bikeId);
            if(rideRecord.getUserId() == userLocationDto.getUserId()&&electricBike.getIsUsing()==1){
                electricBike.setSwitchState(BIKE_SWITCH_ON.getCode());

                updateById(electricBike);
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public PublishSettingMessageVo setting(Integer bikeId, Float lightThreshold, Boolean bool) {
        PublishSettingMessageVo publishMessageVo = new PublishSettingMessageVo();
        try {
            /* 先找到这辆自行车 */
            ElectricBike electricBike = getById(bikeId);
            /* 設置定義參數 */
            electricBike.setLightThreshold(lightThreshold);
            /* 修改参数 */
            updateById(electricBike);
            /* 发送设置 */
            /* 封装好发送类 */

            publishMessageVo.setBright(lightThreshold);
            Integer isSyncTime = bool?1:0;
            publishMessageVo.setIsSyncTime(isSyncTime);
            publishMessageVo.setTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        } catch (Exception e) {
            e.printStackTrace();
            return publishMessageVo;
        }
        return publishMessageVo;
    }

    @Override
    public boolean returnBike(int bikeId, UserLocationDto userLocationDto) {
        try{
            /* 第一步先验证是否是他租赁的，是则关闭bike开关和设置没有使用状态并存入表中 */
            /* 通过最新记录找到这条记录并存入表中 */
            RideRecord latestRideRecord = rideRecordService.getLatestRecordByBikeId(bikeId);
            ElectricBike electricBike = getById(bikeId);
            /* 判断一下是否为正确的记录: 是否是本人在租用 */
            if(latestRideRecord.getUserId() == userLocationDto.getUserId()&&electricBike.getIsUsing()==1){
            electricBike.setSwitchState(BIKE_SWITCH_OFF.getCode());
            electricBike.setIsUsing(BIKE_STATUS_OFF.getCode());
            updateById(electricBike);
            /* 注意租车的起点和终点应该是车的地点而非人的地点 */
            latestRideRecord.setEndTime(new Date(System.currentTimeMillis()));
            latestRideRecord.setEndLongitude(electricBike.getLongitude());
            latestRideRecord.setEndLatitude(electricBike.getLatitude());
            latestRideRecord.setDistance(DistanceUtils.getDistance(latestRideRecord.getStartLongitude(),latestRideRecord.getStartLatitude(),latestRideRecord.getEndLongitude(),latestRideRecord.getEndLatitude()));
            long durationInMillis = latestRideRecord.getEndTime().getTime() - latestRideRecord.getStartTime().getTime();
            float durationInHours = (float) durationInMillis / 3600000;
            latestRideRecord.setDuration(durationInHours);
            latestRideRecord.setAverageSpeed(latestRideRecord.getDistance()/latestRideRecord.getDuration());
            rideRecordService.updateById(latestRideRecord);

            }else {
                return false;
            }
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
    }


    public <T> PageVo getPage(int pageNum, int pageSize,  List<T> sourceList) {
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, sourceList.size());

        if (startIndex > endIndex) {
            return new PageVo(Collections.emptyList(), 0L);
        }

        List<T> pageData = sourceList.subList(startIndex, endIndex);
        Integer total = sourceList.size();
        return new PageVo(pageData, total.longValue());
    }

}

